package tnviet.proj.jna.test;
/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski
ISBN: 1-893115-78-X
Publisher: APress
*/

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;


public class ListProperties {
  static class CustomTableModel extends AbstractTableModel {
    Vector keys = new Vector();

    Vector values = new Vector();

    private static final String columnNames[] = { "Property String",
        "Value" };

    public int getColumnCount() {
      return columnNames.length;
    }

    public String getColumnName(int column) {
      return columnNames[column];
    }

    public int getRowCount() {
      return keys.size();
    }

    public Object getValueAt(int row, int column) {
      Object returnValue = null;
      if (column == 0) {
        returnValue = keys.elementAt(row);
      } else if (column == 1) {
        returnValue = values.elementAt(row);

      }
      return returnValue;
    }

    public synchronized void uiDefaultsUpdate(UIDefaults defaults) {
      Enumeration newKeys = defaults.keys();
      keys.removeAllElements();
      while (newKeys.hasMoreElements()) {
        keys.addElement(newKeys.nextElement());
      }

      Enumeration newValues = defaults.elements();
      values.removeAllElements();
      while (newValues.hasMoreElements()) {
        values.addElement(newValues.nextElement());
      }

      fireTableDataChanged();
    }
  }

  public static void main(String args[]) {
    final JFrame frame = new JFrame("List Properties");

    final CustomTableModel model = new CustomTableModel();
    model.uiDefaultsUpdate(UIManager.getDefaults());
    TableSorter sorter = new TableSorter(model);

    JTable table = new JTable(sorter);
    TableHeaderSorter.install(sorter, table);

    table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);

    UIManager.LookAndFeelInfo looks[] = UIManager
        .getInstalledLookAndFeels();

    ActionListener actionListener = new ActionListener() {
      public void actionPerformed(ActionEvent actionEvent) {
        final String lafClassName = actionEvent.getActionCommand();
        Runnable runnable = new Runnable() {
          public void run() {
            try {
              UIManager.setLookAndFeel(lafClassName);
              SwingUtilities.updateComponentTreeUI(frame);
              // Added
              model.uiDefaultsUpdate(UIManager.getDefaults());
            } catch (Exception exception) {
              JOptionPane.showMessageDialog(frame,
                  "Can't change look and feel",
                  "Invalid PLAF", JOptionPane.ERROR_MESSAGE);
            }
          }
        };
        SwingUtilities.invokeLater(runnable);
      }
    };

    JToolBar toolbar = new JToolBar();
    for (int i = 0, n = looks.length; i < n; i++) {
      JButton button = new JButton(looks[i].getName());
      button.setActionCommand(looks[i].getClassName());
      button.addActionListener(actionListener);
      toolbar.add(button);
    }

    Container content = frame.getContentPane();
    content.add(toolbar, BorderLayout.NORTH);
    JScrollPane scrollPane = new JScrollPane(table);
    content.add(scrollPane, BorderLayout.CENTER);
    frame.setSize(400, 400);
    frame.setVisible(true);
  }
}
class TableSorter extends TableMap implements TableModelListener {
  int indexes[] = new int[0];

  Vector sortingColumns = new Vector();

  boolean ascending = true;

  public TableSorter() {
  }

  public TableSorter(TableModel model) {
    setModel(model);
  }

  public void setModel(TableModel model) {
    super.setModel(model);
    reallocateIndexes();
    sortByColumn(0);
    fireTableDataChanged();
  }

  public int compareRowsByColumn(int row1, int row2, int column) {
    Class type = model.getColumnClass(column);
    TableModel data = model;

    // Check for nulls

    Object o1 = data.getValueAt(row1, column);
    Object o2 = data.getValueAt(row2, column);

    // If both values are null return 0
    if (o1 == null && o2 == null) {
      return 0;
    } else if (o1 == null) { // Define null less than everything.
      return -1;
    } else if (o2 == null) {
      return 1;
    }

    if (type.getSuperclass() == Number.class) {
      Number n1 = (Number) data.getValueAt(row1, column);
      double d1 = n1.doubleValue();
      Number n2 = (Number) data.getValueAt(row2, column);
      double d2 = n2.doubleValue();

      if (d1 < d2)
        return -1;
      else if (d1 > d2)
        return 1;
      else
        return 0;
    } else if (type == String.class) {
      String s1 = (String) data.getValueAt(row1, column);
      String s2 = (String) data.getValueAt(row2, column);
      int result = s1.compareTo(s2);

      if (result < 0)
        return -1;
      else if (result > 0)
        return 1;
      else
        return 0;
    } else if (type == java.util.Date.class) {
      Date d1 = (Date) data.getValueAt(row1, column);
      long n1 = d1.getTime();
      Date d2 = (Date) data.getValueAt(row2, column);
      long n2 = d2.getTime();

      if (n1 < n2)
        return -1;
      else if (n1 > n2)
        return 1;
      else
        return 0;
    } else if (type == Boolean.class) {
      Boolean bool1 = (Boolean) data.getValueAt(row1, column);
      boolean b1 = bool1.booleanValue();
      Boolean bool2 = (Boolean) data.getValueAt(row2, column);
      boolean b2 = bool2.booleanValue();

      if (b1 == b2)
        return 0;
      else if (b1) // Define false < true
        return 1;
      else
        return -1;
    } else {
      Object v1 = data.getValueAt(row1, column);
      String s1 = v1.toString();
      Object v2 = data.getValueAt(row2, column);
      String s2 = v2.toString();
      int result = s1.compareTo(s2);

      if (result < 0)
        return -1;
      else if (result > 0)
        return 1;
      else
        return 0;
    }
  }

  public int compare(int row1, int row2) {
    for (int level = 0, n = sortingColumns.size(); level < n; level++) {
      Integer column = (Integer) sortingColumns.elementAt(level);
      int result = compareRowsByColumn(row1, row2, column.intValue());
      if (result != 0) {
        return (ascending ? result : -result);
      }
    }
    return 0;
  }

  public void reallocateIndexes() {
    int rowCount = model.getRowCount();
    indexes = new int[rowCount];
    for (int row = 0; row < rowCount; row++) {
      indexes[row] = row;
    }
  }

  public void tableChanged(TableModelEvent tableModelEvent) {
    super.tableChanged(tableModelEvent);
    reallocateIndexes();
    sortByColumn(0);
    fireTableStructureChanged();
  }

  public void checkModel() {
    if (indexes.length != model.getRowCount()) {
      System.err.println("Sorter not informed of a change in model.");
    }
  }

  public void sort() {
    checkModel();
    shuttlesort((int[]) indexes.clone(), indexes, 0, indexes.length);
    fireTableDataChanged();
  }

  public void shuttlesort(int from[], int to[], int low, int high) {
    if (high - low < 2) {
      return;
    }
    int middle = (low + high) / 2;
    shuttlesort(to, from, low, middle);
    shuttlesort(to, from, middle, high);

    int p = low;
    int q = middle;

    for (int i = low; i < high; i++) {
      if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
        to[i] = from[p++];
      } else {
        to[i] = from[q++];
      }
    }
  }

  private void swap(int first, int second) {
    int temp = indexes[first];
    indexes[first] = indexes[second];
    indexes[second] = temp;
  }

  public Object getValueAt(int row, int column) {
    checkModel();
    return model.getValueAt(indexes[row], column);
  }

  public void setValueAt(Object aValue, int row, int column) {
    checkModel();
    model.setValueAt(aValue, indexes[row], column);
  }

  public void sortByColumn(int column) {
    sortByColumn(column, true);
  }

  public void sortByColumn(int column, boolean ascending) {
    this.ascending = ascending;
    sortingColumns.removeAllElements();
    sortingColumns.addElement(new Integer(column));
    sort();
    super.tableChanged(new TableModelEvent(this));
  }
}

class TableHeaderSorter extends MouseAdapter {

  private TableSorter sorter;

  private JTable table;

  private TableHeaderSorter() {
  }

  public static void install(TableSorter sorter, JTable table) {
    TableHeaderSorter tableHeaderSorter = new TableHeaderSorter();
    tableHeaderSorter.sorter = sorter;
    tableHeaderSorter.table = table;
    JTableHeader tableHeader = table.getTableHeader();
    tableHeader.addMouseListener(tableHeaderSorter);
  }

  public void mouseClicked(MouseEvent mouseEvent) {
    TableColumnModel columnModel = table.getColumnModel();
    int viewColumn = columnModel.getColumnIndexAtX(mouseEvent.getX());
    int column = table.convertColumnIndexToModel(viewColumn);
    if (mouseEvent.getClickCount() == 1 && column != -1) {
      System.out.println("Sorting ...");
      int shiftPressed = (mouseEvent.getModifiers() & InputEvent.SHIFT_MASK);
      boolean ascending = (shiftPressed == 0);
      sorter.sortByColumn(column, ascending);
    }
  }
}

class TableMap extends AbstractTableModel implements TableModelListener {

  TableModel model;

  public TableModel getModel() {
    return model;
  }

  public void setModel(TableModel model) {
    if (this.model != null) {
      this.model.removeTableModelListener(this);
    }
    this.model = model;
    if (this.model != null) {
      this.model.addTableModelListener(this);
    }
  }

  public Class getColumnClass(int column) {
    return model.getColumnClass(column);
  }

  public int getColumnCount() {
    return ((model == null) ? 0 : model.getColumnCount());
  }

  public String getColumnName(int column) {
    return model.getColumnName(column);
  }

  public int getRowCount() {
    return ((model == null) ? 0 : model.getRowCount());
  }

  public Object getValueAt(int row, int column) {
    return model.getValueAt(row, column);
  }

  public void setValueAt(Object value, int row, int column) {
    model.setValueAt(value, row, column);
  }

  public boolean isCellEditable(int row, int column) {
    return model.isCellEditable(row, column);
  }

  public void tableChanged(TableModelEvent tableModelEvent) {
    fireTableChanged(tableModelEvent);
  }
}


